package com.tbi.graphcolouring.appframe;

import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.Array;
import java.util.Arrays;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.border.EmptyBorder;
import javax.swing.border.TitledBorder;

import com.tbi.algorithm.AlgorithmDataCollectorDecorator;
import com.tbi.algorithm.ConfigurableGenethicAlgorithm;
import com.tbi.algorithm.datacollector.IStopperDataCollector;
import com.tbi.graphcolouring.AlgorithmSettings;
import com.tbi.graphcolouring.GraphFactory;
import com.tbi.graphcolouring.algorithmconfiguration.creator.RandomPopulationCreator;
import com.tbi.graphcolouring.algorithmconfiguration.crosser.MultiPointCrosser;
import com.tbi.graphcolouring.algorithmconfiguration.evaluator.PunishmentEvaluator;
import com.tbi.graphcolouring.algorithmconfiguration.evaluator.RepairEvaluator;
import com.tbi.graphcolouring.algorithmconfiguration.mutator.SinglePointMutator;
import com.tbi.graphcolouring.algorithmconfiguration.selector.ExponentialRankingSelector;
import com.tbi.graphcolouring.algorithmconfiguration.selector.GaussianRankingSelector;
import com.tbi.graphcolouring.algorithmconfiguration.selector.TournamentSelector;
import com.tbi.graphcolouring.algorithmconfiguration.stopper.GenerationStopper;
import com.tbi.graphcolouring.algorithmconfiguration.stopper.NoImprovementStopper;
import com.tbi.graphcolouring.datacollector.AlgorithmStopDataCollector;
import com.tbi.graphcolouring.largestfirst.LargestFirstAlgorithm;
import com.tbi.graphcolouring.testers.PlotPanel;

import net.miginfocom.swing.MigLayout;
import javax.swing.JLabel;

@SuppressWarnings("serial")
public class MainFrame extends JFrame {

	private JPanel contentPane;
	
	private JPanel chartPanel;

	/**
	 * Launch the application.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {
			public void run() {
				try {
					UIManager.setLookAndFeel(
				            UIManager.getSystemLookAndFeelClassName());
					MainFrame frame = new MainFrame();
					
					//set up AlgorithmSettings
					AlgorithmSettings.populationCreator = new RandomPopulationCreator(AlgorithmSettings.POPULATION_SIZE);
					AlgorithmSettings.evaluator = new RepairEvaluator(AlgorithmSettings.graph);
					AlgorithmSettings.algorithmStopper = new NoImprovementStopper(AlgorithmSettings.GENERATIONS_WITHOUT_IMPROVEMENT_LIMIT);
					AlgorithmSettings.selector = new GaussianRankingSelector();
					AlgorithmSettings.crosser = new MultiPointCrosser();
					AlgorithmSettings.mutator = new SinglePointMutator();
					
					
					frame.setVisible(true);
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}

	/**
	 * Create the frame.
	 */
	public MainFrame() {
		setTitle("Artificial Intelligence - genethic algorithm");
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		contentPane = new JPanel();
		contentPane.setBorder(new EmptyBorder(5, 5, 5, 5));
		setContentPane(contentPane);
		contentPane.setLayout(new MigLayout("", "[][][][grow][grow]", "[grow][][80px:n:80px][75px:n:75px,grow]"));
		
		final JButton loadButton = new JButton("Load");
		contentPane.add(loadButton, "cell 0 1");
		
		final JButton configButton = new JButton("Config");
		contentPane.add(configButton, "cell 1 1");
		
		final JButton runButton = new JButton("Run");
		runButton.setEnabled(false);
		contentPane.add(runButton, "cell 2 1");
		
		final JPanel resultsPanel = new JPanel();
		resultsPanel.setBorder(new TitledBorder(UIManager.getBorder("TitledBorder.border"), "Genethic algorithm results", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		contentPane.add(resultsPanel, "cell 3 1 2 2,grow");
		resultsPanel.setLayout(new MigLayout("", "[90px:n:90px][]", "[][][][]"));
		
		final JLabel lblBestRating = new JLabel("Best rating ever:");
		resultsPanel.add(lblBestRating, "cell 0 0");
		
		final JLabel bestRatingResult = new JLabel("");
		resultsPanel.add(bestRatingResult, "cell 1 0");
		
		final JLabel lblAverageRating = new JLabel("Average rating:");
		resultsPanel.add(lblAverageRating, "cell 0 1");
		
		final JLabel averageRatingResult = new JLabel("");
		resultsPanel.add(averageRatingResult, "cell 1 1");
		
		final JLabel lblWorstRating = new JLabel("Last worst rating:");
		resultsPanel.add(lblWorstRating, "cell 0 2");
		
		final JLabel worstRatingResult = new JLabel("");
		resultsPanel.add(worstRatingResult, "cell 1 2");
		
		final JLabel lblTime = new JLabel("Time:");
		resultsPanel.add(lblTime, "cell 0 3");
		
		final JLabel timeResult = new JLabel("");
		resultsPanel.add(timeResult, "cell 1 3");
		
		final JPanel panel = new JPanel();
		panel.setBorder(new TitledBorder(null, "Loaded graph", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		contentPane.add(panel, "cell 0 2 3 1,grow");
		panel.setLayout(new MigLayout("", "[]", "[][][]"));
		
		final JLabel nodesLabel = new JLabel("None");
		panel.add(nodesLabel, "cell 0 0");
		
		final JLabel edgesLabel = new JLabel("");
		panel.add(edgesLabel, "cell 0 1");
		
		final JLabel filenameLabel = new JLabel("");
		panel.add(filenameLabel, "cell 0 2");
		
		final JPanel panel_1 = new JPanel();
		panel_1.setBorder(new TitledBorder(null, "Largest First algorithm results", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		contentPane.add(panel_1, "cell 3 3 2 1,grow");
		panel_1.setLayout(new MigLayout("", "[90px:n:90px][]", "[][]"));
		
		final JLabel lblRating = new JLabel("Rating:");
		panel_1.add(lblRating, "cell 0 0");
		
		final JLabel lfRatingResult = new JLabel("");
		panel_1.add(lfRatingResult, "cell 1 0");
		
		final JLabel lblTime_1 = new JLabel("Time:");
		panel_1.add(lblTime_1, "cell 0 1");
		
		final JLabel lfTimeResult = new JLabel("");
		panel_1.add(lfTimeResult, "cell 1 1");
		
		setUpChartPanel(null);
		this.pack();
		
		loadButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				JFileChooser filechooser = new JFileChooser("graphs");
				int returnVal = filechooser.showOpenDialog(MainFrame.this);

		        if (returnVal == JFileChooser.APPROVE_OPTION) {
		            File f = filechooser.getSelectedFile();
		            try {
						MainFrame.this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
						AlgorithmSettings.graph = GraphFactory.load(f.getCanonicalPath());
						MainFrame.this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
						AlgorithmSettings.evaluator.setGraph(AlgorithmSettings.graph);
					} catch (IOException e) { e.printStackTrace(); }
		            runButton.setEnabled(true);
		            
		            nodesLabel.setText("Nodes: "+UIModel.model.get("nodes_number"));
		            edgesLabel.setText("Edges: "+UIModel.model.get("edges_number"));
		            filenameLabel.setText("File: "+UIModel.model.get("filename"));
		        }
			}
		});

		configButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				ConfigDialog.open(MainFrame.this);
			}
		});

		runButton.addActionListener(new ActionListener() {
			public void actionPerformed(ActionEvent arg0) {
				Thread t = new Thread(new Runnable() {
					private long time;
					
					@Override
					public void run() {
						before();
						
						ConfigurableGenethicAlgorithm algorithm = new ConfigurableGenethicAlgorithm();
						
						algorithm.setCrosser(AlgorithmSettings.crosser);
						algorithm.setEvaluator(AlgorithmSettings.evaluator);
						algorithm.setMutator(AlgorithmSettings.mutator);
						algorithm.setPopulationCreator(AlgorithmSettings.populationCreator);
						algorithm.setSelector(AlgorithmSettings.selector);
						algorithm.setStopper(AlgorithmSettings.algorithmStopper);
						
						AlgorithmDataCollectorDecorator algorithmDataCollector = new AlgorithmDataCollectorDecorator(algorithm);
						
						final AlgorithmStopDataCollector dataCollector = new AlgorithmStopDataCollector();
						algorithmDataCollector.setAlgorithmStopDataCollector(dataCollector);
						
						long start = System.currentTimeMillis();
						algorithmDataCollector.doIt(AlgorithmSettings.graph);
						time = System.currentTimeMillis() - start;
						
						after(dataCollector);
					}
					
					private void before(){
						runButton.setEnabled(false);
						configButton.setEnabled(false);
						loadButton.setEnabled(false);
						MainFrame.this.setCursor(new Cursor(Cursor.WAIT_CURSOR));
					}
					
					private void after(AlgorithmStopDataCollector dataCollector){
						setUpChartPanel(dataCollector);
						
						timeResult.setText(time+"ms");
						bestRatingResult.setText(dataCollector.getBestEver().rating+"");
						averageRatingResult.setText(dataCollector.getAverageEntity(dataCollector.getGenerations()-1)+"");
						worstRatingResult.setText(dataCollector.getWorstEntity(dataCollector.getGenerations()-1).rating+"");
						
						LargestFirstAlgorithm lfa = new LargestFirstAlgorithm(AlgorithmSettings.graph);
						lfa.doIt();
						
						lfTimeResult.setText(lfa.getTime()+"ms");
						lfRatingResult.setText(lfa.getRating()+"");
						
						runButton.setEnabled(true);
						configButton.setEnabled(true);
						loadButton.setEnabled(true);
						MainFrame.this.setCursor(new Cursor(Cursor.DEFAULT_CURSOR));
					}
				});
				
				t.start();
			}
		});
		
		setLocationRelativeTo(null);
		setSize(700, 650);
	}

	private void setUpChartPanel(IStopperDataCollector dataCollector){
		if(chartPanel != null){
			contentPane.remove(chartPanel);
		}
		
		chartPanel = PlotPanel.getInstance(dataCollector);
		chartPanel.setBorder(new TitledBorder(null, "Chart", TitledBorder.LEADING, TitledBorder.TOP, null, null));
		contentPane.add(chartPanel, "cell 0 0 5 1,grow");
		
		this.revalidate();
	}
}
